/*
 * Copyright (C) 2008-2009 the original author or authors
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *         http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.code.liquidform;

import java.util.Date;

import com.google.code.liquidform.conditions.ConditionalExpression;
import com.google.code.liquidform.internal.AliasFactory;

/**
 * Represents the optional <tt>GROUP BY</tt> part of the query. An instance of
 * this can be spawned from {@link FromClause#groupBy(Object...)} or from
 * {@link ConditionalExpressionFactor#groupBy(Object...)}.
 * 
 * @param <S>
 *            the type that was selected by the {@link SelectClause SELECT
 *            construct}
 */
public class GroupByClause<S> extends AbstractClause implements SubQuery<S> {

	private final Object[] groupers;

	/* default */GroupByClause(WhereClause<S> whereClause, Object[] groupers) {
		super(whereClause);
		this.groupers = groupers;
	}

	/* default */GroupByClause(FromClause<?, S> fromClause, Object[] groupers) {
		super(fromClause);
		this.groupers = groupers;
	}

	@Override
	StringBuilder addTo(StringBuilder buffer) {
		buffer.append(" group by ");
		for (int i = 0; i < groupers.length; i++) {
			Object grouper = groupers[i];
			buffer.append(AliasFactory.about(grouper)
					.getPreferredStringRepresentation());
			if (i < groupers.length - 1) {
				buffer.append(", ");
			}
		}
		return buffer;
	}

	// ============================ H A V I N G ================================
	public HavingClause<S> having(ConditionalExpression condition) {
		return new HavingClause<S>(this, condition);
	}

	// ============================ O R D E R B Y ==========================
	public OrderByClause orderBy(Number o) {
		return this.orderBy(o, SortDirection.ASC);
	}

	public OrderByClause orderBy(Number o, SortDirection dir) {
		return new OrderByClause(this, o, dir);
	}

	public OrderByClause orderBy(Date o) {
		return this.orderBy(o, SortDirection.ASC);
	}

	public OrderByClause orderBy(Date o, SortDirection dir) {
		return new OrderByClause(this, o, dir);
	}

	public OrderByClause orderBy(String o) {
		return this.orderBy(o, SortDirection.ASC);
	}

	public OrderByClause orderBy(String o, SortDirection dir) {
		return new OrderByClause(this, o, dir);
	}

	public OrderByClause orderBy(Character o) {
		return this.orderBy(o, SortDirection.ASC);
	}

	public OrderByClause orderBy(Character o, SortDirection dir) {
		return new OrderByClause(this, o, dir);
	}

	// TODO : legal or not?
	// public OrderByClause orderBy(Enum o) {
	// return this.orderBy(o, SortDirection.ASC);
	// }
	//
	// public OrderByClause orderBy(Enum o, SortDirection dir) {
	// return new OrderByClause(this, o, dir);
	// }

}
